package cn.demoncat.util.word;

import cn.demoncat.util.exception.IoRuntimeException;
import cn.demoncat.util.io.CloseUtil;
import cn.demoncat.util.io.FileNameUtil;
import cn.demoncat.util.io.IoUtil;
import cn.demoncat.util.web.ServletUtil;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import org.apache.poi.poifs.crypt.HashAlgorithm;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.function.Consumer;

/**
 * Word模板工具
 *
 * @see <a href="http://deepoove.com/poi-tl">poi-tl</a>
 *
 * 注：只支持 docx
 *
 * @author 延晓磊
 *
 * @since 2020年6月3日
 */
public class WordTemplateUtil {

	/**
	 * 添加密码的只读处理器
	 * 
	 * @param password
	 * @return
	 * 
	 * @author 延晓磊
	 * @since 2024年02月28日
	 */
	public static Consumer<XWPFTemplate> getReadonlyHandler(String password){
		 return t -> t.getXWPFDocument().enforceReadonlyProtection(password, HashAlgorithm.sha512);

	}
	
	/**
	 * 渲染Word文档 A1
	 * 
	 * @param in	模板文档
	 * @param out	输出文档
	 * @param data	数据：Map、Object、RenderData
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年6月3日
	 */
	public static void render(InputStream in, OutputStream out, Object data) {
		render(in, out, data, null, null);
	}

	/**
	 * 渲染Word文档 A1
	 *
	 * @param in	模板文档
	 * @param out	输出文档
	 * @param data	数据：Map、Object、RenderData
	 * @param handler 文档处理器
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年6月3日
	 */
	public static void render(InputStream in, OutputStream out, Object data, Consumer<XWPFTemplate> handler) {
		render(in, out, data, null, handler);
	}

	/**
	 * 渲染Word文档 A2
	 *
	 * @param in	模板文档
	 * @param out	输出文档
	 * @param data	数据：Map、Object、RenderData
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年6月3日
	 */
	public static void render(String in, OutputStream out, Object data) {
		render(IoUtil.getInputStreamByPath(in), out, data);
	}

	/**
	 * 渲染Word文档 A2
	 *
	 * @param in	模板文档
	 * @param out	输出文档
	 * @param data	数据：Map、Object、RenderData
	 * @param handler 文档处理器
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年6月3日
	 */
	public static void render(String in, OutputStream out, Object data, Consumer<XWPFTemplate> handler) {
		render(IoUtil.getInputStreamByPath(in), out, data, handler);
	}

	/**
	 * 渲染Word文档 B1
	 *
	 * @param in	模板文档
	 * @param out	输出文档
	 * @param data	数据：Map、Object、RenderData
	 * @param config 配置：用于复杂数据渲染，例 Configure.builder().bind("materials", new LoopRowTableRenderPolicy()).build()
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年6月3日
	 */
	public static void render(InputStream in, OutputStream out, Object data, Configure config) {
		render(in, out, data, config, null);
	}

	/**
	 * 渲染Word文档 B1
	 *
	 * @param in	模板文档
	 * @param out	输出文档
	 * @param data	数据：Map、Object、RenderData
	 * @param config 配置：用于复杂数据渲染，例 Configure.builder().bind("materials", new LoopRowTableRenderPolicy()).build()
	 * @param handler 文档处理器
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年6月3日
	 */
	public static void render(InputStream in, OutputStream out, Object data, Configure config, Consumer<XWPFTemplate> handler) {
		// 读取模板
		XWPFTemplate template = config == null ? XWPFTemplate.compile(in) : XWPFTemplate.compile(in, config);
		try {
			// 渲染文档
			template.render(data);
			// 处理档
			if (handler != null) {
				handler.accept(template);
			}
			// 输出文档
			template.write(out);
		} catch (IOException e) {
			throw new IoRuntimeException("渲染Word文档失败", e);
		}finally {
			// 关闭流
			CloseUtil.flush(out);
			CloseUtil.close(template);
			CloseUtil.close(out);
		}
	}

	/**
	 * 渲染Word文档 B2
	 *
	 * @param in	模板文档
	 * @param out	输出文档
	 * @param data	数据：Map、Object、RenderData
	 * @param config 配置：用于复杂数据渲染，例 Configure.builder().bind("materials", new LoopRowTableRenderPolicy()).build()
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年6月3日
	 */
	public static void render(String in, OutputStream out, Object data, Configure config) {
		render(IoUtil.getInputStreamByPath(in), out, data, config);
	}

	/**
	 * 渲染Word文档 B2
	 *
	 * @param in	模板文档
	 * @param out	输出文档
	 * @param data	数据：Map、Object、RenderData
	 * @param config 配置：用于复杂数据渲染，例 Configure.builder().bind("materials", new LoopRowTableRenderPolicy()).build()
	 * @param handler 文档处理器
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年6月3日
	 */
	public static void render(String in, OutputStream out, Object data, Configure config, Consumer<XWPFTemplate> handler) {
		render(IoUtil.getInputStreamByPath(in), out, data, config, handler);
	}

	/**
	 * 渲染Word文档 C1
	 *
	 * @param in	模板路径：绝对路径、相对路径（基于ClassPath，如 *resources/wtl/1.docx = wtl/1.docx）、网络路径（http开头）
	 * @param data	数据：Map、Object、RenderData
	 * @param fileName      文件名，需要后缀
	 * @param response
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年6月3日
	 */
	public static void render(InputStream in, Object data, String fileName, HttpServletResponse response) {
		render(in, ServletUtil.getDownloadOut(response, fileName), data);
	}

	/**
	 * 渲染Word文档 C1
	 *
	 * @param in	模板路径：绝对路径、相对路径（基于ClassPath，如 *resources/wtl/1.docx = wtl/1.docx）、网络路径（http开头）
	 * @param data	数据：Map、Object、RenderData
	 * @param fileName      文件名，需要后缀
	 * @param response
	 * @param handler 文档处理器
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年6月3日
	 */
	public static void render(InputStream in, Object data, String fileName, HttpServletResponse response, Consumer<XWPFTemplate> handler) {
		render(in, ServletUtil.getDownloadOut(response, fileName), data, handler);
	}

	/**
	 * 渲染Word文档 C2
	 *
	 * @param in	模板路径：绝对路径、相对路径（基于ClassPath，如 *resources/wtl/1.docx = wtl/1.docx）、网络路径（http开头）
	 * @param data	数据：Map、Object、RenderData
	 * @param fileName      文件名，不需要后缀
	 * @param response
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年6月3日
	 */
	public static void render(String in, Object data, String fileName, HttpServletResponse response) {
		render(in, ServletUtil.getDownloadOut(response, fileName + FileNameUtil.getSuffix(in)), data);
	}

	/**
	 * 渲染Word文档 C2
	 *
	 * @param in	模板路径：绝对路径、相对路径（基于ClassPath，如 *resources/wtl/1.docx = wtl/1.docx）、网络路径（http开头）
	 * @param data	数据：Map、Object、RenderData
	 * @param fileName      文件名，不需要后缀
	 * @param response
	 * @param handler 文档处理器
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年6月3日
	 */
	public static void render(String in, Object data, String fileName, HttpServletResponse response, Consumer<XWPFTemplate> handler) {
		render(in, ServletUtil.getDownloadOut(response, fileName + FileNameUtil.getSuffix(in)), data, handler);
	}

	/**
	 * 渲染Word文档 D1
	 *
	 * @param in	模板路径：绝对路径、相对路径（基于ClassPath，如 *resources/wtl/1.docx = wtl/1.docx）、网络路径（http开头）
	 * @param data	数据：Map、Object、RenderData
	 * @param config 配置：用于复杂数据渲染
	 * @param fileName      文件名，需要后缀
	 * @param response
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年6月3日
	 */
	public static void render(InputStream in, Object data, Configure config, String fileName, HttpServletResponse response) {
		render(in, ServletUtil.getDownloadOut(response, fileName), data, config);
	}

	/**
	 * 渲染Word文档 D1
	 *
	 * @param in	模板路径：绝对路径、相对路径（基于ClassPath，如 *resources/wtl/1.docx = wtl/1.docx）、网络路径（http开头）
	 * @param data	数据：Map、Object、RenderData
	 * @param config 配置：用于复杂数据渲染
	 * @param fileName      文件名，需要后缀
	 * @param response
	 * @param handler 文档处理器
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年6月3日
	 */
	public static void render(InputStream in, Object data, Configure config, String fileName, HttpServletResponse response, Consumer<XWPFTemplate> handler) {
		render(in, ServletUtil.getDownloadOut(response, fileName), data, config, handler);
	}

	/**
	 * 渲染Word文档 D2
	 *
	 * @param in	模板路径：绝对路径、相对路径（基于ClassPath，如 *resources/wtl/1.docx = wtl/1.docx）、网络路径（http开头）
	 * @param data	数据：Map、Object、RenderData
	 * @param config 配置：用于复杂数据渲染
	 * @param fileName      文件名，不需要后缀
	 * @param response
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年6月3日
	 */
	public static void render(String in, Object data, Configure config, String fileName, HttpServletResponse response) {
		 render(in, ServletUtil.getDownloadOut(response, fileName + FileNameUtil.getSuffix(in)), data, config);
	}

	/**
	 * 渲染Word文档 D2
	 *
	 * @param in	模板路径：绝对路径、相对路径（基于ClassPath，如 *resources/wtl/1.docx = wtl/1.docx）、网络路径（http开头）
	 * @param data	数据：Map、Object、RenderData
	 * @param config 配置：用于复杂数据渲染
	 * @param fileName      文件名，不需要后缀
	 * @param response
	 * @param handler 文档处理器
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年6月3日
	 */
	public static void render(String in, Object data, Configure config, String fileName, HttpServletResponse response, Consumer<XWPFTemplate> handler) {
		render(in, ServletUtil.getDownloadOut(response, fileName + FileNameUtil.getSuffix(in)), data, config, handler);
	}


}
